package com.github.wujichen158.andemusic.eventsetting;

import com.github.wujichen158.andemusic.AndeMusic;
import com.github.wujichen158.andemusic.aboutconfig.AndeMusicConfig;
import com.github.wujichen158.andemusic.playernbt.MusicCapability;
import com.github.wujichen158.andemusic.playernbt.MusicTypeProvider;
import net.minecraft.client.Minecraft;
import net.minecraft.client.audio.ISound;
import net.minecraft.client.audio.MusicTicker;
import net.minecraft.client.audio.PositionedSoundRecord;
import net.minecraft.util.SoundEvent;
import net.minecraft.util.math.MathHelper;
import net.minecraftforge.event.entity.player.PlayerEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.TickEvent;
import net.minecraftforge.fml.relauncher.ReflectionHelper;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

import java.io.File;
import java.lang.reflect.Field;
import java.util.Optional;
import java.util.Random;

public class MusicPlayer {
    public static String musicName = AndeMusicConfig.defaultMusicName;
    public static Field MusicField = null;
    public static Object PreMusicField = null;
    public static Object PrePreMusicField = null;
    public static boolean isInGame = false;

    @SideOnly(Side.CLIENT)
    @SubscribeEvent
    public void onLoad(PlayerEvent.LoadFromFile event) {
        File playerData = new File(event.getPlayerDirectory(), event.getPlayerUUID() + ".dat");

        if (!playerData.exists()) {
            Optional.ofNullable(MusicTypeProvider.get(event.getEntityPlayer())).ifPresent(capability -> {
                capability.setMusicType(AndeMusicConfig.defaultMusicName);
                capability.setMinDelayTime(AndeMusicConfig.minWaitTime);
                capability.setMaxDelayTime(AndeMusicConfig.maxWaitTime);
            });
        }
    }

    @SideOnly(Side.CLIENT)
    @SubscribeEvent
    public void onClientTick(TickEvent.ClientTickEvent event) {
        try {
            Minecraft mc = Minecraft.getMinecraft();
            if (MusicField == null) {
                MusicField = ReflectionHelper.findField(Minecraft.class, new String[]{"mcMusicTicker", "field_147126_aw"});
            }

            if (MusicField != null && PrePreMusicField == null) {
                PrePreMusicField = MusicField.get(mc);
            }

            if (PrePreMusicField != null && PreMusicField == null) {
                SoundEvent sound = MusicRegister.getSound(AndeMusicConfig.defaultTitleMusicName);
                if (sound == null) {
                    PreMusicField = MusicField.get(mc);
                } else {
                    PreMusicField = new EnhancedMusicTicker(mc, sound);
                    MusicField.set(mc, PreMusicField);
                }
            }

            if (MusicField != null && PreMusicField != null && event.phase == TickEvent.Phase.START) {
                if (mc.world != null) {
                    if (musicName != null){
                        SoundEvent sound = MusicRegister.getSound(musicName);
                        if (sound != null) {
                            MusicField.set(mc, new EnhancedMusicTicker(mc, sound));
                            resetFields();
                        } else if (musicName.isEmpty() && PrePreMusicField != null) {
                            MusicField.set(mc, PrePreMusicField);
                            resetFields();
                        }
                    }
                } else if (isInGame) {
                    MusicField.set(mc, PreMusicField);
                    isInGame = false;
                }
            }
        } catch (IllegalAccessException | IllegalArgumentException e) {
            AndeMusic.LOGGER.error(e);
        }
    }

    @SideOnly(Side.CLIENT)
    public void resetFields() {
        isInGame = true;
        musicName = null;
        Minecraft.getMinecraft().getSoundHandler().stopSounds();
    }

    @SideOnly(Side.CLIENT)
    public static class EnhancedMusicTicker extends MusicTicker {
        public static int minWait = MusicCapability.minDelayTime;
        public static int maxWait = MusicCapability.maxDelayTime;
        public SoundEvent sound;
        public Random RNG;
        public Minecraft mc;
        public ISound currentSound;
        public int timeUntilMusic;

        public EnhancedMusicTicker(Minecraft mc, SoundEvent sound) {
            super(mc);
            this.RNG = new Random();
            this.timeUntilMusic = MusicCapability.minDelayTime / 10;
            this.mc = mc;
            this.sound = sound;
        }

        @Override
        public void update() {
            if (this.currentSound != null) {
                if (!this.sound.getSoundName().equals(this.currentSound.getSoundLocation())) {
                    this.mc.getSoundHandler().stopSound(this.currentSound);
                    this.timeUntilMusic = MathHelper.getInt(this.RNG, 0, minWait / 2);
                }
                if (!this.mc.getSoundHandler().isSoundPlaying(this.currentSound)) {
                    this.currentSound = null;
                    this.timeUntilMusic = Math.min(MathHelper.getInt(this.RNG, minWait, maxWait), this.timeUntilMusic);
                }
            }

            if (this.currentSound == null && this.timeUntilMusic-- <= 0) {
                this.currentSound = PositionedSoundRecord.getMusicRecord(this.sound);
                this.mc.getSoundHandler().playSound(this.currentSound);
                this.timeUntilMusic = Integer.MAX_VALUE;
            }
        }
    }
}